package edu.maping.easy.painter.plugins;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.Map;

import controlP5.ControlP5;

import processing.core.PApplet;
import processing.core.PImage;
import processing.core.PVector;
import codeanticode.glgraphics.GLGraphicsOffScreen;
import ddf.minim.analysis.FFT;
import deadpixel.keystone.CornerPinSurface;
import edu.maping.easy.ControlFacade;
import edu.maping.easy.fisica.EasyMappingFPoly;
import edu.maping.easy.gui.ButtonList;
import edu.maping.easy.gui.GUIEvent;
import edu.maping.easy.gui.GuiFactory;
import edu.maping.easy.model.Point;
import edu.maping.easy.model.PolygonThing;
import edu.maping.easy.model.Thing;
import edu.maping.easy.model.World;
import edu.maping.easy.painter.EventPainter;
import edu.maping.easy.painter.ThingPainterDelegate;
import edu.maping.easy.painter.UtilPainter;
import edu.maping.easy.painter.cornerpin.CornerPin;
import edu.maping.easy.painter.napplet.EMNAppletAdapter;
import edu.maping.easy.sequence.ActionConf;
import edu.maping.easy.sequence.ticker.TickerListener;
import fisica.FBlob;
import fisica.FBody;
import fisica.FBox;
import fisica.FWorld;
import fisica.Fisica;

public class FisicaRenderer extends EMNAppletAdapter {

	private UtilPainter utilPainter = new UtilPainter();

	public FWorld world = null;
	ControlP5 controlP5;

	Float density = 10F;
	Float restitutions = 0.5F;
	Float isStatic = 0F;

	Map<String, Float> controllers = new HashMap<String, Float>();

	boolean started = false;

	Map<Thing, EasyMappingFPoly> thingPolyRelations = new HashMap<Thing, EasyMappingFPoly>();
	Map<EasyMappingFPoly, Thing> polyThingRelations = new HashMap<EasyMappingFPoly, Thing>();

	FBox top = null;

	public void setup(){
		Fisica.init(this);

		initFisica();
//		this.pApplet = pApplet;
		// initControl(controlFacade);
		// world.setEdges();
		// world.remove(world.left);
		// world.remove(world.right);
		// world.remove(world.top);
		setTop();
	}

	public void draw() {
		
			top.setPosition(width / 2, -5);
			top.setWidth(width);
			if ((frameCount % 20) == 1) {
				addBubble();
			}

			// FFT fft = fftFacade.getFft();
			//
			// float avg = fft.calcAvg(0, fft.avgSize() - 1);
			//
			// float step = avg / 1024F;
			// if (step < 0.01) {
			// step = 0.01F;
			// } else if (step > 0.8) {
			// step = 0.8F;
			// }
			//
			// world.step(step);

			float x = 0;
			float y = 0;

			world.draw();

			//pApplet.ellipse(x, y, 25, 21);
	}

	public void draw(Thing cosa, PApplet pApplet, Object object) {
	}

	private void addBubble() {

		float s = random(20, 35);
		float x = random(width+15, width-15);

		FBlob b = new FBlob();
		// FCircle b = new FCircle(s);
		// b.setPosition(x, pApplet.height - pApplet.random(100, 110));
		b.setAsCircle(x, height - random(100, 110), s, 20);
		b.setStroke(0);
		b.setStrokeWeight(0);
		b.setFill(random(255), random(255), random(255));
		world.add(b);
	}

	public void draw(Thing body, PApplet pApplet) {
		draw(body, pApplet, null);

	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see
	 * edu.maping.easy.painter.plugins.TimeRunner#stop(edu.maping.easy.model
	 * .World, processing.core.PApplet, controlP5.ControlP5)
	 */
//	@Override
	public void stop(World world, PApplet pApplet, ControlP5 controlP5) {
		started = false;
		ArrayList<FBody> bodies = this.world.getBodies();
		// for (FBody fBody : bodies) {
		// this.world.removeBody(fBody);
		// }
		initFisica();
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see
	 * edu.maping.easy.painter.plugins.TimeRunner#start(edu.maping.easy.model
	 * .World, processing.core.PApplet, controlP5.ControlP5)
	 */
//	@Override
	public void start(World world, PApplet pApplet, ControlP5 controlP5) {
		this.controlP5 = controlP5;

		ArrayList<Thing> things = world.getWorld();
		for (Thing thing : things) {
			if (thing instanceof PolygonThing) {

				PolygonThing physicPolyThing = (PolygonThing) thing;

				EasyMappingFPoly fPoly = new EasyMappingFPoly();

				fPoly.setRestitution(restitutions);
				fPoly.setDensity(density);

				fPoly.setStatic(true);

				fPoly.setNoFill();

				for (Point p : physicPolyThing.vertex) {
					PVector pVector = surface.getTransformedCursor(p.x, p.y);
					fPoly.vertex(pVector.x, pVector.y);
				}

				this.world.add(fPoly);

				thingPolyRelations.put(thing, fPoly);
				polyThingRelations.put(fPoly, thing);
			}
		}

		started = true;
	}

	public void turnOn() {

	}

	@Override
	public void setConf(ActionConf actionConf) {
	}

	@Override
	public String getName() {
		return "Fisica Renderer";
	}

	@Override
	public EventPainter controlEvent(GUIEvent theEvent) {
		EventPainter eventPainter = utilPainter.controlEvent(theEvent);
		if (eventPainter != null)
			setParameters(eventPainter.name, eventPainter.value);
		return eventPainter;
	}

	public void setParameters(String name, float value) {

		if (name.equals("Fisica Renderer")) {
			// openPath();
		}
	}

	@Override
	public void showForm(int x, int y) {
		utilPainter.setPosition(x, y);
		utilPainter.render();
	}

	@Override
	public void hideForm() {
		utilPainter.hide();
	}

	public ActionConf createNewActionConf() {
		return utilPainter.createActionConf();
	}

	@Override
	public ThingPainterDelegate createNewInstance() {
		
		Object object = parentNAppletManager.createEmbeddedNApplet(this
				.getClass().getName(), 200, 200);
		FisicaRenderer fisica = (FisicaRenderer)object;
		
		fisica.utilPainter = utilPainter.clone();
		
		return fisica;
	}

	private void initFisica() {
		world = new FWorld(320, 240);
		world.setGravity(0, -300);
	}

	public void setTop() {
		top = new FBox(width, 20);
		top.setStaticBody(true);
		top.setGrabbable(false);
		top.setPosition(width / 2, -5);
		top.setFillColor(0);
		top.setStrokeColor(0);
		world.addBody(top);
	}

	@Override
	public void setup(PApplet pApplet, ControlFacade controlFacade,
			ButtonList buttonList, GuiFactory guiFactory) {
		// TODO Auto-generated method stub

	}

}
